#include "stdafx.h"


HBITMAP Create24BPPDIBSection(HDC hDC, int iWidth, int iHeight)
{
	BITMAPINFO bmi;
	HBITMAP hbm;
	LPBYTE pBits;

	ZeroMemory(&bmi, sizeof(bmi));

	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = iWidth;
	bmi.bmiHeader.biHeight = iHeight;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 24;
	bmi.bmiHeader.biCompression = BI_RGB;

	hbm = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);

	return(hbm);
}

BOOL BitmapCompatible(LPBITMAP lpbm1, LPBITMAP lpbm2)
{
	if (lpbm1->bmBitsPixel	!= lpbm2->bmBitsPixel)	return FALSE;
	if (lpbm1->bmPlanes		!= lpbm2->bmPlanes)		return FALSE;
	if (lpbm1->bmWidth		!= lpbm2->bmWidth)		return FALSE;
	if (lpbm1->bmHeight		!= lpbm2->bmHeight)		return FALSE;
	return TRUE;
}

BOOL BlendImages(HBITMAP hbmSrc1, HBITMAP hbmSrc2, HBITMAP hbmDst, DWORD dwWeight1)
{
	BITMAP bmSrc1, bmSrc2, bmDst;
	RGBTRIPLE *lprgbSrc1, *lprgbSrc2, *lprgbDst;
	DWORD dwWidthBytes, dwWeight2;
	int x,y;

	if(dwWeight1 > 255) return FALSE;

	dwWeight2 = 255-dwWeight1;

	if(!GetObject(hbmSrc1, sizeof(BITMAP), &bmSrc1))	return FALSE;
	if(!GetObject(hbmSrc2, sizeof(BITMAP), &bmSrc2))	return FALSE;
	if(!GetObject(hbmDst, sizeof(BITMAP), &bmDst))		return FALSE;
	
	if(!BitmapCompatible(&bmSrc1, &bmSrc2))				return FALSE;
	if(!BitmapCompatible(&bmSrc1, &bmDst))				return FALSE;
	if(bmSrc1.bmBitsPixel != 24)						return FALSE;
	if(bmSrc1.bmPlanes != 1)							return FALSE;
	if(!bmSrc1.bmBits || !bmSrc2.bmBits || !bmDst.bmBits)	return FALSE;
	dwWidthBytes = bmDst.bmWidthBytes;

	lprgbSrc1 = (RGBTRIPLE *)bmSrc1.bmBits;
	lprgbSrc2 = (RGBTRIPLE *)bmSrc2.bmBits;
	lprgbDst = (RGBTRIPLE *)bmDst.bmBits;
	for(y=0; y<bmDst.bmHeight; y++)
	{
		for(x=0; x<bmDst.bmWidth; x++)
		{
			lprgbDst[x].rgbtRed		= (BYTE)((((DWORD)lprgbSrc1[x].rgbtRed*dwWeight1) + ((DWORD)lprgbSrc2[x].rgbtRed*dwWeight2)) >> 8);
			lprgbDst[x].rgbtGreen	= (BYTE)((((DWORD)lprgbSrc1[x].rgbtGreen*dwWeight1) + ((DWORD)lprgbSrc2[x].rgbtGreen*dwWeight2)) >> 8);
			lprgbDst[x].rgbtBlue	= (BYTE)((((DWORD)lprgbSrc1[x].rgbtBlue*dwWeight1) + ((DWORD)lprgbSrc2[x].rgbtBlue*dwWeight2)) >> 8);
		}
		lprgbSrc1 = (RGBTRIPLE *)((LPBYTE)lprgbSrc1 + dwWidthBytes);
		lprgbSrc2 = (RGBTRIPLE *)((LPBYTE)lprgbSrc2 + dwWidthBytes);
		lprgbDst = (RGBTRIPLE *)((LPBYTE)lprgbDst + dwWidthBytes);
	}
	return TRUE;
}

BOOL DoAlphaBlend(
  HDC	hdcDest,
  int nXOriginDest,
  int nYOriginDest,
  int nWidthDest,
  int nHeightDest,
  HDC hdcSrc,
  int nXOriginSrc,
  int nYOriginSrc,
  int nWidthSrc,
  int nHeightSrc,
  DWORD dwSourceWeight)
{
	HDC	hdcSrc1 = NULL;
	HDC	hdcSrc2 = NULL;
	HDC	hdcDst = NULL;
	HBITMAP	hbmSrc1 = NULL;
	HBITMAP	hbmSrc2 = NULL;
	HBITMAP	hbmDst = NULL;

	BOOL	bReturn;

	hbmSrc1 = Create24BPPDIBSection(hdcDest, nWidthDest, nHeightDest);
	if (!hbmSrc1) goto HANDLEERROR;
	hbmSrc2 = Create24BPPDIBSection(hdcDest, nWidthDest, nHeightDest);
	if (!hbmSrc2) goto HANDLEERROR;
	hbmDst = Create24BPPDIBSection(hdcDest, nWidthDest, nHeightDest);
	if (!hbmDst) goto HANDLEERROR;

	hdcSrc1 = CreateCompatibleDC(hdcDest);
	if(!hdcSrc1) goto HANDLEERROR;
	hdcSrc2 = CreateCompatibleDC(hdcDest);
	if(!hdcSrc2) goto HANDLEERROR;
	hdcDst = CreateCompatibleDC(hdcDest);
	if(!hdcDst) goto HANDLEERROR;

	SelectObject(hdcSrc1, hbmSrc1);
	SelectObject(hdcSrc2, hbmSrc2);
	SelectObject(hdcDst, hbmDst);
	SetStretchBltMode(hdcSrc1, COLORONCOLOR);
	SetStretchBltMode(hdcSrc2, COLORONCOLOR);

	if(!StretchBlt(hdcSrc1, 0, 0, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY))
		goto HANDLEERROR;

	if(!StretchBlt(hdcSrc2, 0, 0, nWidthDest, nHeightDest, hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightSrc, SRCCOPY))
		goto HANDLEERROR;

	bReturn= BlendImages(hbmSrc1, hbmSrc2, hbmDst, dwSourceWeight);

	DeleteDC(hdcSrc1);
	DeleteDC(hdcSrc2);
	DeleteObject(hbmSrc1);
	DeleteObject(hbmSrc2);

	if(bReturn)
		BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcDst, 0, 0, SRCCOPY);

	DeleteDC(hdcDst);
	DeleteObject(hbmDst);

HANDLEERROR:
	if(hdcSrc1) DeleteDC(hdcSrc1);
	if(hdcSrc2) DeleteDC(hdcSrc2);
	if(hdcDst) DeleteDC(hdcDst);
	if(hbmSrc1) DeleteObject(hbmSrc1);
	if(hbmSrc2) DeleteObject(hbmSrc2);
	if(hbmDst) DeleteObject(hbmDst);
	return FALSE;
}



/////////////////////////////////////////////////////////////////////////////////////////////////////

//	COLORREF	0x00bbggrr
//	DIBRGB		0x00rrggbb

#define COLORREF2DIBRGB(clr)	\
	((((clr) << 16) & 0x00ff0000)	|\
	( (clr)        & 0x0000ff00)	|\
	(((clr) >> 16) & 0x000000ff))

#define GetDibR(drgb)	(((drgb) & 0x00ff0000) >> 16)
#define GetDibG(drgb)	(((drgb) & 0x0000ff00) >>  8)
#define GetDibB(drgb)	 ((drgb) & 0x000000ff)

#define DIBRGB2COLORREF(clr)	COLORREF2DIBRGB(clr)

COLORREF	m_clrGradient[256];


void CreateGradient(
					  COLORREF	clrLight	/* = RGB(255,255,255) */,
					  COLORREF	clrDark		/* = RGB(  0,  0,  0) */)
{
	for(int i=0; i<256; i++)
	{
		m_clrGradient[i] = RGB(
			(GetRValue(clrLight) * i + GetRValue(clrDark) * (255 - i)) >> 8,
			(GetGValue(clrLight) * i + GetGValue(clrDark) * (255 - i)) >> 8,
			(GetBValue(clrLight) * i + GetBValue(clrDark) * (255 - i)) >> 8 );
	}
}


HBITMAP FadeBitmap(
					 HBITMAP		hBmp,
					 double			dfTrans,
					 HDC			hBmpDC)
{
	HBITMAP hRetBmp = NULL;

	if (hBmp)
	{
		// DC for Source Bitmap
		HDC hBufferDC = CreateCompatibleDC(NULL);
		if (hBufferDC)
		{
			HBITMAP hTmpBitmap = (HBITMAP) NULL;
			if (hBmpDC)
				if (hBmp == (HBITMAP)GetCurrentObject(hBmpDC, OBJ_BITMAP))
				{
					hTmpBitmap = CreateBitmap(1, 1, 1, 1, NULL);
					SelectObject(hBmpDC, hTmpBitmap);
				}

				// here hBufferDC contains the bitmap
				HGDIOBJ hPrevBufObject = SelectObject(hBufferDC, hBmp);

				HDC hDirectDC = CreateCompatibleDC(NULL);	// DC for working		
				if (hDirectDC)
				{
					// Get bitmap size
					BITMAP bm;
					GetObject(hBmp, sizeof(bm), &bm);

					// create a BITMAPINFO with minimal initilisation for the CreateDIBSection
					BITMAPINFO bmInfo; 
					ZeroMemory(&bmInfo,sizeof(bmInfo));
					bmInfo.bmiHeader.biSize		= sizeof(BITMAPINFOHEADER);
					bmInfo.bmiHeader.biWidth	= bm.bmWidth;
					bmInfo.bmiHeader.biHeight	= bm.bmHeight;
					bmInfo.bmiHeader.biPlanes	=  1;
					bmInfo.bmiHeader.biBitCount	= 32;

					UINT* ptPixels;	// pointer used for direct Bitmap pixels access

					HBITMAP hDirectBitmap = CreateDIBSection(hDirectDC, (BITMAPINFO*)&bmInfo, DIB_RGB_COLORS,(void**)&ptPixels, NULL, 0);
					if (hDirectBitmap)
					{
						// here hDirectBitmap!=NULL so ptPixels!=NULL no need to test
						HGDIOBJ hPrevBufDirObject = SelectObject(hDirectDC, hDirectBitmap);
						BitBlt(hDirectDC,0,0,bm.bmWidth,bm.bmHeight,hBufferDC,0,0,SRCCOPY);					

						// process loop

						// A cool new implementation made by Mikko Mononen
						//   Coder: http://www.codeproject.com/script/profile/whos_who.asp?id=41615
						//   Found: http://www.codeproject.com/dialog/WinMakeInactive.asp?select=656456&df=100&forumid=25834#xx656456xx

						int iAlpha = (int)(255.0 * dfTrans / 100.0);

						int nSize = bm.bmWidth * bm.bmHeight;
						for (int i=0; i<nSize; i++)
						{
							// Calcuate grey
							// See Color Space FAQ at: http://www.faqs.org/faqs/graphics/colorspace-faq/
							// 0.212671 * R + 0.715160 * G + 0.072169 * B
							int iSrcR = GetDibR(ptPixels[i]);
							int iSrcG = GetDibG(ptPixels[i]);
							int iSrcB = GetDibB(ptPixels[i]);
							int iGrey = (iSrcR * 54 + iSrcG * 182 + iSrcB * 19) >> 8;

							// Take color from the gradient
							COLORREF Col = m_clrGradient[iGrey]; // You may want to try claming here...

							ptPixels[i] = RGB(
								(GetBValue( Col ) * iAlpha + iSrcB * (255 - iAlpha)) >> 8,
								(GetGValue( Col ) * iAlpha + iSrcG * (255 - iAlpha)) >> 8,
								(GetRValue( Col ) * iAlpha + iSrcR * (255 - iAlpha)) >> 8 );
						}

						// little clean up
						// Don't delete the result of SelectObject because it's our modified bitmap (hDirectBitmap)
						SelectObject(hDirectDC,hPrevBufDirObject);

						// finish
						hRetBmp = hDirectBitmap;
					}

					// clean up
					DeleteDC(hDirectDC);
				}

				if (hTmpBitmap)
				{
					SelectObject(hBmpDC, hBmp);
					DeleteObject(hTmpBitmap);
				}

				SelectObject(hBufferDC, hPrevBufObject);

				// hBufferDC is now useless
				DeleteDC(hBufferDC);
		}
	}

	return hRetBmp;
}


HBITMAP CopyScreenToBitmap(LPRECT lpRect)
{
	HDC	hScrDC, hMemDC;			// screen DC and memory DC     
	int	nX, nY, nX2, nY2;		// coordinates of rectangle to grab     
	int	nWidth, nHeight;		// DIB width and height     
	int	xScrn,  yScrn;			// screen resolution      

	HGDIOBJ	hOldBitmap, hBitmap;

	// check for an empty rectangle 
	if (IsRectEmpty(lpRect))       
		return NULL;      

	// create a DC for the screen and create
	// a memory DC compatible to screen DC
	hScrDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);     
	hMemDC = CreateCompatibleDC(hScrDC);

	// get points of rectangle to grab  
	nX  = lpRect->left;     
	nY  = lpRect->top;     
	nX2 = lpRect->right;
	nY2 = lpRect->bottom;

	// get screen resolution      
	xScrn = GetDeviceCaps(hScrDC, HORZRES);     
	yScrn = GetDeviceCaps(hScrDC, VERTRES);      

	// make sure bitmap rectangle is visible      
	if (nX  < 0)		nX = 0;     
	if (nY  < 0)		nY = 0;     
	if (nX2 > xScrn)	nX2 = xScrn;     
	if (nY2 > yScrn)	nY2 = yScrn;      

	nWidth	= nX2 - nX;     
	nHeight	= nY2 - nY;      

	// create a bitmap compatible with the screen DC     
	hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);      

	// select new bitmap into memory DC     
	hOldBitmap = SelectObject(hMemDC, hBitmap);      

	// bitblt screen DC to memory DC     
	BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);     

	// select old bitmap back into memory DC and get handle to     
	// bitmap of the screen          
	hBitmap = SelectObject(hMemDC, hOldBitmap);      

	// clean up      
	DeleteDC(hScrDC);     
	DeleteDC(hMemDC);      

	// return handle to the bitmap      
	return (HBITMAP)hBitmap; 
}
